import element from "./element";
let container = document.getElementById("root");
const PLACEMENT = "PLACEMENT";
// 模拟fiber的链表结构
let workInProgressRoot = {
  stateNode: container, //fiber对应真实dom对象
  props: { children: [element] }, //fiber的属性
};
// 下一个工作单元
let nextUnitOfWork = workInProgressRoot;

function workLoop(deadline) {
  debugger;
  // 如果nextUnitOfWork存在，就执行，并返回一个工作单元nextUnitOfWork
  while (nextUnitOfWork) {
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
  }
  // 如果么有下一个节点，说明完成了第一个阶段Reconciliation
  if (!nextUnitOfWork) {
    // 接下来开始第二个render阶段，执行提交插入
    commitRoot();
  }
}

function commitRoot() {
  let currentFiber = workInProgressRoot.firstEffect;
  while (currentFiber) {
    // console.log("commitRoot", currentFiber.props.id);
    if (currentFiber.effectTag === PLACEMENT) {
      currentFiber.return.stateNode.appendChild(currentFiber.stateNode);
    }
    currentFiber = currentFiber.nextEffect;
  }
  workInProgressRoot = null;
}

function performUnitOfWork(workingInProgressFiber) {
  // 第一步：创建此fiber的虚拟dom 通过虚拟dom创建fiber树结构
  beginWork(workingInProgressFiber);
  // 如果有child，返回child
  if (workingInProgressFiber.child) {
    return workingInProgressFiber.child;
  }
  while (workingInProgressFiber) {
    // 如果没有child节点，说明当前节点已经完成任务
    completeUnitOfWork(workingInProgressFiber);
    // 如果有弟弟节点，返回sibling节点
    if (workingInProgressFiber.sibling) {
      return workingInProgressFiber.sibling;
    }
    // child sibling都没有了，则返回父节点
    workingInProgressFiber = workingInProgressFiber.return;
  }
}

/**
 * @description: beginWork,1.创建真实dom【此时不会挂载dom】，2，创建Fiber树
 */
function beginWork(workingInProgressFiber) {
  console.log("beginWork", workingInProgressFiber.props.id);
  if (!workingInProgressFiber.stateNode) {
    // 创建fiber的真实dom元素，并赋值给fiber的stateNode
    workingInProgressFiber.stateNode = document.createElement(
      workingInProgressFiber.type
    );
    for (let key in workingInProgressFiber.props) {
      if (key !== "children") {
        workingInProgressFiber.stateNode[key] =
          workingInProgressFiber.props[key];
      }
    }
  }
  // 创建上一个子fiber
  let previousFiber;
  if (Array.isArray(workingInProgressFiber.props.children)) {
    // children是一个虚拟dom数组
    workingInProgressFiber.props.children.forEach((child, index) => {
      let childFiber = {
        type: child.type,
        props: child.props,
        return: workingInProgressFiber,
        effectTag: PLACEMENT, //这个fiber对应的dom节点需要被插入到页面中， 父级DOM中
        nextEffect: null, //下一个有副作用的节点
      };
      // 如果index为0，说明是子元素中的第一个，大儿子节点
      if (index === 0) {
        workingInProgressFiber.child = childFiber; //将创建出来的Fiber对象赋值给大儿子节点
      } else {
        // 如果不是第一个，则说明previousFiber已经有值
        // 把新创建出来的childFiber 赋值给previousFiber.sibling的属性，作为上一个fiber 的兄弟节点
        previousFiber.sibling = childFiber;
      }
      previousFiber = childFiber; // 把创建出来的childFiber赋值给前一个的Fiber
    });
  }
}

/**
 * @description:
 * @param {*} workingInProgressFiber
 * @return {*}
 */
function completeUnitOfWork(workingInProgressFiber) {
  console.log("workingInProgressFiber", workingInProgressFiber.props.id);
  // 构建副作用链effectList， 只统计有副作用的节点
  let returnFiber = workingInProgressFiber.return;
  if (returnFiber) {
    // 如果说父级没有 firstEffect副作用，则把子级【当前正在执行的】的firstEffect赋值给父级，
    // 比如B1开始没有firstEffect，就把C1的firstEffect赋值给B1
    if (!returnFiber.firstEffect) {
      returnFiber.firstEffect = workingInProgressFiber.firstEffect;
    }

    if (workingInProgressFiber.lastEffect) {
      // 如果父级有lastEffect，则把父级的lastEffect副作用的nextEffect指向，当前节点的firstEffect
      // 比如，遍历C2节点是，此时B1的lastEffect就有值为C1。所以开始链表关系
      // returnFiber.lastEffect为C1，  C1.nextEffect = C2
      if (returnFiber.lastEffect) {
        returnFiber.lastEffect.nextEffect = workingInProgressFiber.firstEffect;
      }
      // 给父级的lastEffect副作用赋值
      returnFiber.lastEffect = workingInProgressFiber.lastEffect;
    }

    // 子的都完成后，把自己挂载到链最后
    if (workingInProgressFiber.effectTag) {
      // 父节点有 lastEffect时
      if (returnFiber.lastEffect) {
        returnFiber.lastEffect.nextEffect = workingInProgressFiber;
      }
      // 父节点没有 lastEffect属性
      else {
        // 给父节点设置 firstEffect节点，把当前节点赋值给父节点的firstEffect。比如把C1赋值给B1的firstEffect
        returnFiber.firstEffect = workingInProgressFiber;
      }
      // 给父节点 的lastEffect 赋值为当前节点，比如把B1的lastEffect 设置为 C1节点
      returnFiber.lastEffect = workingInProgressFiber;
    }
  }
}
// 告诉浏览器，在一帧主要任务执行完成后，还有空闲时间时执行workLoop
export default function () {
  requestIdleCallback(workLoop);
}
